#include <cstdio>                                                                                                      
#include <set>
#include <cstring>
#include <cstdlib>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <queue>
#include "wn.h"
#include <map>
#define NOUN 1

using namespace std;

static string do_is_defined(char *searchword)
{
    int i, found = 0;
    unsigned int search;
    char *morphword;

    /* Print all valid searches for word in all parts of speech */

    strtolower(strsubst(searchword, ' ', '_'));
	    
    i = NOUN; //noun
    if ((search = is_defined(searchword, i)) != 0) 
    {
        return searchword;
    } 
    return "";
}
typedef struct{
    long hereiam;
    string defn;
    vector<string> words;
} ANCESTOR;
typedef struct{
    long hereiam;		/* current file position */
    string defn;			/* synset gloss (definition) */
    vector<ANCESTOR> ancestors;
} NODE;

void getAncestors(SynsetPtr synsetPtr, vector<ANCESTOR> &ancestors)
{
    for (int i = 0; i < synsetPtr->ptrcount; ++i)
    {
        if (synsetPtr->ptrtyp[i] == HYPERPTR)
        {
            ANCESTOR ancestor;
            int pos = synsetPtr->ppos[i]; 
            int offset = synsetPtr->ptroff[i];
            SynsetPtr freePtr = read_synset(pos, offset, "");
            synsetPtr = freePtr;
            ancestor.hereiam = synsetPtr->hereiam;
            ancestor.defn = string(synsetPtr->defn);
            for (int j = 0; j < synsetPtr->wcount; ++j)
            {
                ancestor.words.push_back(synsetPtr->words[j]);
            }
            ancestors.push_back(ancestor);
            getAncestors(synsetPtr, ancestors);
            free_syns(freePtr);
            break;
        }
    }
}

vector<NODE> getInfo(char* word, int pos, int type, int whichsense)
{
    vector<NODE> nodes;
    SynsetPtr freePtr = findtheinfo_ds(word, pos, type, whichsense);
    SynsetPtr synsetPtr = freePtr;
    while(synsetPtr)
    {
        NODE node;
        vector<ANCESTOR> ancestors;
        node.hereiam = synsetPtr->hereiam;
        node.defn = string(synsetPtr->defn);
        getAncestors(synsetPtr, ancestors);
        node.ancestors = ancestors;
        nodes.push_back(node);
        synsetPtr = synsetPtr->nextss;
    }
    free_syns(freePtr);
    return nodes;
}

void print(vector<NODE> &nodes, ofstream &output, string left)
{
    for (int i = 0; i < nodes.size(); ++i)
    {
        output << left << "                <synset>" << endl;
        output << left << "                    <offset>" << nodes[i].hereiam << "</offset>" << endl;
        output << left << "                    <defination>" << nodes[i].defn << "</defination>" << endl;
        for (int j = 0; j < nodes[i].ancestors.size(); ++j)
        {
            output << left << "                    <ancestor>" << endl;
            output << left << "                        <offset>" << nodes[i].ancestors[j].hereiam << "</offset>" << endl;
            output << left << "                        <defination>" << nodes[i].ancestors[j].defn << "</defination>" << endl;
            string words = nodes[i].ancestors[j].words[0];
            for (int k = 1; k < nodes[i].ancestors[j].words.size(); ++k)
            {
                words += ", " + nodes[i].ancestors[j].words[k];
            }
            output << left << "                        <words>" << words << "</words>" << endl;
            output << left << "                    </ancestor>" << endl;
        }
        output << left << "                </synset>" << endl;
    }
}

string strip(string s)
{
    if (s[0] == ' ')
    {
        return s.substr(1);
    }
    if (s[s.size() - 1] == ' ')
    {
        return s.substr(0, s.size() - 1);
    }
    return s;
}

vector<string> analyze(string left)
{
    vector<string> lefts;
    int index = left.find(" and ");
    if (index != -1)
    {
        int leftOne = left.rfind(' ', index - 1);
        int leftTwo = index;
        int rightOne = index + 4;
        int rightTwo = left.find(' ', rightOne + 1);
        string one = "";
        string two = "";
        string three = "";
        string four = "";
        if (leftOne > 0)
        {
            one = left.substr(0, leftOne);
        }
        if (leftTwo > 0)
        {
            two = left.substr(0, leftTwo);
        }
        if (rightOne > 0)
        {
            three = left.substr(rightOne + 1);
        }
        if (rightTwo > 0)
        {
            four = left.substr(rightTwo + 1);
        }
        string t1 = one + " " + three;
        string t2 = two + " " + four;
        t1 = strip(t1);
        t2 = strip(t2);
        vector<string> v1 = analyze(t1);
        vector<string> v2 = analyze(t2);
        for (int i = 0; i < v1.size(); ++i)
        {
            lefts.push_back(v1[i]);
        }
        for (int i = 0; i < v2.size(); ++i)
        {
            lefts.push_back(v2[i]);
        }
        return lefts;
    }
    else
    {
        index = left.find(" or ");
        if (index != -1)
        {
            int leftOne = left.rfind(' ', index - 1);
            int leftTwo = index;
            int rightOne = index + 3;
            int rightTwo = left.find(' ', rightOne + 1);
            string one = "";
            string two = "";
            string three = "";
            string four = "";
            if (leftOne > 0)
            {
                one = left.substr(0, leftOne);
            }
            if (leftTwo > 0)
            {
                two = left.substr(0, leftTwo);
            }
            if (rightOne > 0)
            {
                three = left.substr(rightOne + 1);
            }
            if (rightTwo > 0)
            {
                four = left.substr(rightTwo + 1);
            }
            string t1 = one + " " + three;
            string t2 = two + " " + four;
            t1 = strip(t1);
            t2 = strip(t2);
            vector<string> v1 = analyze(t1);
            vector<string> v2 = analyze(t2);
            for (int i = 0; i < v1.size(); ++i)
            {
                lefts.push_back(v1[i]);
            }
            for (int i = 0; i < v2.size(); ++i)
            {
                lefts.push_back(v2[i]);
            }
            return lefts;
        }
        else
        {
            index = left.find(" , ");
            if (index != -1)
            {
                int leftOne = left.rfind(' ', index - 1);
                int leftTwo = index;
                int rightOne = index + 2;
                int rightTwo = left.find(' ', rightOne + 1);
                string one = "";
                string two = "";
                string three = "";
                string four = "";
                if (leftOne > 0)
                {
                    one = left.substr(0, leftOne);
                }
                if (leftTwo > 0)
                {
                    two = left.substr(0, leftTwo);
                }
                if (rightOne > 0)
                {
                    three = left.substr(rightOne + 1);
                }
                if (rightTwo > 0)
                {
                    four = left.substr(rightTwo + 1);
                }
                string t1 = one + " " + three;
                string t2 = two + " " + four;
                t1 = strip(t1);
                t2 = strip(t2);
                vector<string> v1 = analyze(t1);
                vector<string> v2 = analyze(t2);
                for (int i = 0; i < v1.size(); ++i)
                {
                    lefts.push_back(v1[i]);
                }
                for (int i = 0; i < v2.size(); ++i)
                {
                    lefts.push_back(v2[i]);
                }
                return lefts;
            }
            else
            {
                index = left.find(", ");
                if (index != -1)
                {
                    int leftOne = left.rfind(' ', index);
                    int leftTwo = index;
                    int rightOne = index + 1;
                    int rightTwo = left.find(' ', rightOne + 1);
                    string one = "";
                    string two = "";
                    string three = "";
                    string four = "";
                    if (leftOne > 0)
                    {
                        one = left.substr(0, leftOne);
                    }
                    if (leftTwo > 0)
                    {
                        two = left.substr(0, leftTwo);
                    }
                    if (rightOne > 0)
                    {
                        three = left.substr(rightOne + 1);
                    }
                    if (rightTwo > 0)
                    {
                        four = left.substr(rightTwo + 1);
                    }
                    string t1 = one + " " + three;
                    string t2 = two + " " + four;
                    t1 = strip(t1);
                    t2 = strip(t2);
                    vector<string> v1 = analyze(t1);
                    vector<string> v2 = analyze(t2);
                    for (int i = 0; i < v1.size(); ++i)
                    {
                        lefts.push_back(v1[i]);
                    }
                    for (int i = 0; i < v2.size(); ++i)
                    {
                        lefts.push_back(v2[i]);
                    }
                    return lefts;
                }
                lefts.push_back(left);
                return lefts;
            }
        }
    }
    
}

int main()
{
    ifstream purposes;
    purposes.open("purpose.suffix.dedup");
    ofstream indirect;
    indirect.open("indirect.xml");
    if (wninit()) {		// open database 
	    cerr <<"wn: Fatal error - cannot open WordNet database" << endl;
	    exit (-1);
    }
    string temp;
    indirect << "<xml>" << endl;
    int indirectNumber = 0;
    int indirectMultiCount = 0;
    int totalsynset = 0;
    int multiSubPurpose = 0;
    while (getline(purposes, temp))
    {
        string name = temp;
        indirect << "    <item>" << endl;
        indirect << "        <name>" << name << "</name>" << endl;
        vector<string> subs = analyze(name);
        set<string> unique;
        for (int i = 0; i < subs.size(); ++i)
        {
            unique.insert(subs[i]);
        }
        indirect << "        <subPatternNumber>" << unique.size() << "</subPatternNumber>" << endl;
        if (unique.size() > 1)
        {
            multiSubPurpose++;
        }
        set<string>::iterator iter;
        for (iter = unique.begin(); iter != unique.end(); ++iter)
        {
            name = *iter;
            indirect << "        <subPattern>" << endl;
            indirect << "            <subPatternName>" << name << "</subPatternName>" << endl;
            int start = 0;
            if (unique.size() == 1)
            {
                start = name.find(' ', start);
            }
            while (start >= 0)
            {
                string tempname, t;
                if (start == 0)
                {
                    tempname = name.substr(start);
                    t = name.substr(start);
                }
                else
                {
                    tempname = name.substr(start + 1);
                    t = name.substr(start + 1);
                }
                if (!string(do_is_defined(const_cast<char*>(t.c_str()))).empty())
                {
                    indirectNumber++;
                    indirect << "            <motherPurpose>" << endl;
                    indirect << "                <motherName>" << tempname << "</motherName>" << endl;
                    vector<NODE> nodes = getInfo(const_cast<char*>(t.c_str()), NOUN, OVERVIEW, ALLSENSES);
                    totalsynset += nodes.size();
                    if (nodes.size() > 1)
                    {
                        indirectMultiCount++;
                    }
                    indirect << "                <synsetCount>" << nodes.size() << "</synsetCount>" << endl;
                    print(nodes, indirect, "");
                    indirect << "            </motherPurpose>" << endl;
                    string left = name.substr(0, start);
                    if (!left.empty())
                    {
                        indirect << "            <left>" << endl;
                        indirect << "                <leftName>" << left << "</leftName>" << endl;
                        start = 0;
                        while (start >= 0)
                        {
                            string lefttempname, leftt;
                            if (start == 0)
                            {
                                lefttempname = left.substr(start);
                                leftt = left.substr(start);
                            }
                            else
                            {
                                lefttempname = left.substr(start + 1);
                                leftt = left.substr(start + 1);
                            }
                            if (!string(do_is_defined(const_cast<char*>(leftt.c_str()))).empty())
                            {
                                indirect << "                <lefttrunk>" << endl;
                                indirect << "                    <trunkName>" << lefttempname << "</trunkName>" << endl;
                                vector<NODE> leftnodes = getInfo(const_cast<char*>(leftt.c_str()), NOUN, OVERVIEW, ALLSENSES);
                                indirect << "                    <synsetCount>" << leftnodes.size() << "</synsetCount>" << endl;
                                print(leftnodes, indirect, "    ");
                                indirect << "                </lefttrunk>" << endl;
                                break;
                            }
                            start = left.find(' ', start + 1);
                        }
                        indirect << "            </left>" << endl;
                    }
                    break;
                }
                start = name.find(' ', start + 1);
            }
            indirect << "        </subPattern>" << endl;
        }
        indirect << "    </item>" << endl;
    }
    indirect << "</xml>" << endl;
    cout << "indirect match number = " << indirectNumber << endl;
    cout << "indirect poly mother synsets item number = " << indirectMultiCount << endl;
    cout << "average mother synset number = " << totalsynset * 1.0 / indirectNumber << endl;
    cout << "multi purposes number = " <<  multiSubPurpose << endl;
    purposes.close();
    indirect.close();
}
